﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

using Caliburn.Micro;

using Microsoft.Practices.Unity;

using TheKitchen.Client.Services;
using TheKitchen.Client.ViewModels;

namespace TheKitchen.Client
{
    public class ClientBootstrapper : Bootstrapper<MainViewModel>
    {
        private readonly IUnityContainer container = new UnityContainer();

        /// <summary>
        ///   Override to configure the framework and setup your IoC container.
        /// </summary>
        protected override void Configure()
        {
            RegisterTypes();
            AddElementConventions();
        }

        private void RegisterTypes()
        {
            var mainViewModel = container.Resolve<MainViewModel>();
            container.RegisterInstance(mainViewModel);
            container.RegisterInstance<IBusyService>(mainViewModel);
            container.RegisterType<IEventAggregator, EventAggregator>(new ContainerControlledLifetimeManager());
            container.RegisterType<ICommandAgent, CommandAgent>(new ContainerControlledLifetimeManager());
            container.RegisterType<IQueryAgent, QueryAgent>(new ContainerControlledLifetimeManager());
            container.RegisterType<IWindowManager, WindowManager>(new ContainerControlledLifetimeManager());
        }

        protected override void OnStartup(object sender, StartupEventArgs e)
        {
            base.OnStartup(sender, e);
            IDictionary<string, string> parameters = e.InitParams;
            
            var queryAgent = container.Resolve<QueryAgent>();
            queryAgent.QueryContextUri = new Uri(parameters["QueryServiceURI"]);
            var commandAgent = container.Resolve<CommandAgent>();
            commandAgent.CommandServiceUri = new Uri(parameters["CommandServiceURI"]);
        }


        private static void AddElementConventions()
        {
            ConventionManager.AddElementConvention<Rating>(Rating.ValueProperty, "Value", "ValueChanged");
            ConventionManager.AddElementConvention<DataGrid>(DataGrid.ItemsSourceProperty, "DataContext", "Loaded");
        }

        /// <summary>
        /// Override this to provide an IoC specific implementation.
        /// </summary>
        /// <param name="service">The service to locate.</param>
        /// <param name="key">The key to locate.</param>
        /// <returns>The located service.</returns>
        protected override object GetInstance(Type service, string key)
        {
            if (service == null)
            {
                service = GetViewModelTypeNameFromKey(key);
                key = "";
            }

            return container.Resolve(service, key);
        }

        private static Type GetViewModelTypeNameFromKey(string key)
        {
            return Type.GetType(typeof (SearchViewModel).Namespace + "." + key);
        }

        /// <summary>
        /// Override this to provide an IoC specific impelentation
        /// </summary>
        /// <param name="service">The service to locate.</param>
        /// <returns>The located services.</returns>
        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return container.ResolveAll(service);
        }

        /// <summary>
        /// Override this to provide an IoC specific implementation.
        /// </summary>
        /// <param name="instance">The instance to perform injection on.</param>
        protected override void BuildUp(object instance)
        {
            container.BuildUp(instance.GetType(), instance);
        }

        protected override void OnUnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            // If the app is running outside of the debugger then report the exception using
            // a ChildWindow control.
            if (!System.Diagnostics.Debugger.IsAttached)
            {
                // NOTE: This will allow the application to continue running after an exception has been thrown
                // but not handled. 
                // For production applications this error handling should be replaced with something that will 
                // report the error to the website and stop the application.
                e.Handled = true;
                ChildWindow errorWin = new ErrorWindow(e.ExceptionObject);
                errorWin.Show();
            }
        }
    }
}